home *** CD-ROM | disk | FTP | other *** search
/ Macwelt 1 / Macwelt DVD 1.toast / Web-Publishing / HTML-Editoren / Alpha ƒ / Mode Examples / C++-Example.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-10-30  |  5.4 KB  |  216 lines

  1. // C++-Example.c
  2. // 
  3. // Included in the Alpha distribution as an example of the C++ mode
  4. // 
  5. // source of original document:
  6. // 
  7. // http://www.research.att.com/~bs
  8. // 
  9. // copywrite (c) 1985 Bjarne Stroustrup
  10. // <bs@research.att.com>
  11.  
  12.  
  13. // The desk calculator
  14. // 
  15. // reads from std::cin 
  16. // uses namespaces, but no exceptions
  17. // 
  18. // The C++ Programming Language, pp 163-171, sec 8.2, Namespaces
  19.  
  20.  
  21. // uses += rather than push_back() for string
  22. // to work around standard library bug
  23.  
  24. // No guarantees offered. Constructive comments to bs@research.att.com
  25.  
  26. /*
  27.         program:
  28.                 END                        // END is end-of-input
  29.                 expr_list END
  30.  
  31.         expr_list:
  32.                 expression PRINT           // PRINT is ';'
  33.                 expression PRINT expr_list
  34.  
  35.         expression:
  36.                 expression + term
  37.                 expression - term
  38.                 term
  39.  
  40.         term:
  41.                 term / primary
  42.                 term * primary
  43.                 primary
  44.  
  45.         primary:
  46.                 NUMBER
  47.                 NAME
  48.                 NAME = expression
  49.                 - primary
  50.                 ( expression )
  51. */
  52.  
  53. #include<iostream>
  54. #include<map>
  55. #include<string>
  56. #include<cctype>
  57.  
  58. // note: no "using namespace std;"
  59.  
  60. namespace Error {
  61.  
  62.         int no_of_errors;
  63.  
  64.         double error(const char* s)
  65.         {
  66.                         cerr << "error: " << s << '\n';
  67.                         no_of_errors++;
  68.                         return 1;
  69.         }
  70. }
  71.  
  72. namespace Lexer {
  73.  
  74.         enum Token_value {
  75.                 NAME,   NUMBER,         END,
  76.                 PLUS='+',       MINUS='-',      MUL='*',        DIV='/',
  77.                 PRINT=';',      ASSIGN='=',     LP='(',         RP=')'
  78.         };
  79.  
  80.         Token_value curr_tok;
  81.         double number_value;
  82.         string string_value;
  83.  
  84.         Token_value get_token();
  85. }
  86.  
  87.  
  88. Lexer::Token_value Lexer::get_token()
  89. {
  90.         char ch = 0;
  91.         cin>>ch;
  92.  
  93.         switch (ch) {
  94.         case 0:
  95.                 return END;
  96.         case ';':
  97.                 return curr_tok=PRINT;
  98.         case '*':
  99.         case '/':
  100.         case '+':
  101.         case '-':
  102.         case '(':
  103.         case ')':
  104.         case '=':
  105.                 return curr_tok=Token_value(ch);
  106.         case '0': case '1': case '2': case '3': case '4':
  107.         case '5': case '6': case '7': case '8': case '9':
  108.         case '.':
  109.                 cin.putback(ch);
  110.                 cin >> number_value;
  111.                 return curr_tok=NUMBER;
  112.         default:                        // NAME, NAME =, or error
  113.                 if (isalpha(ch)) {      // warning isalpha is a macro
  114.                                         // in some implementations
  115.                         std::cin.putback(ch);
  116.                         std::cin>>string_value;
  117.                         return curr_tok=NAME;
  118.                 }
  119.                 Error::error("bad token");
  120.                 return curr_tok=PRINT;
  121.         }
  122. }
  123.  
  124. map<string,double> table;       // global; see sec9.???
  125.  
  126. namespace Parser {
  127.         double prim(bool get);          // handle primaries
  128.         double term(bool get);          // multiply and divide
  129.         double expr(bool get);          // add and subtract
  130.  
  131.         using Lexer::get_token;         // commonly used names
  132.         using Lexer::curr_tok;
  133.         using Error::error;
  134. }
  135.  
  136. double Parser::prim(bool get)           // handle primaries
  137. {
  138.         if (get) get_token();
  139.  
  140.         switch (curr_tok) {
  141.         case Lexer::NUMBER:     // floating point constant
  142.                 get_token();
  143.                 return Lexer::number_value;
  144.         case Lexer::NAME:
  145.         {       double& v = table[Lexer::string_value];
  146.                 if (get_token() == Lexer::ASSIGN) v = expr(1);
  147.                 return v;
  148.         }
  149.         case Lexer::MINUS:              // unary minus
  150.                 return -prim(1);
  151.         case Lexer::LP:
  152.         {       double e = expr(1);
  153.                 if (curr_tok != Lexer::RP) return error(") expected");
  154.                 get_token();                      // eat ')'
  155.                 return e;
  156.         }
  157.         case Lexer::END:
  158.                 return 1;
  159.         default:
  160.                 return error("primary expected");
  161.         }
  162. }
  163.  
  164. double Parser::term(bool get)           // multiply and divide
  165. {
  166.         double left = prim(get);
  167.  
  168.         for (;;)
  169.         switch (curr_tok) {
  170.         case Lexer::MUL:
  171.                 left *= prim(true);
  172.                 break;
  173.         case Lexer::DIV:
  174.                 if (double d = prim(true)) {
  175.                 left /= d;
  176.                         break;
  177.                 }
  178.                 return error("divide by 0");
  179.         default:
  180.                 return left;
  181.         }
  182. }
  183.  
  184. double Parser::expr(bool get)           // add and subtract
  185. {
  186.         double left = term(get);        
  187.  
  188.         for(;;)                 // ``forever''
  189.         switch (curr_tok) {
  190.         case Lexer::PLUS:
  191.                 left += term(true);
  192.                 break;
  193.         case Lexer::MINUS:
  194.                 left -= term(true);
  195.                 break;
  196.         default:
  197.                 return left;
  198.                 }
  199. }
  200.  
  201. int main(int argc, char* argv[])
  202. {
  203.         // insert pre-defined names:
  204.         table["pi"] = 3.1415926535897932385;
  205.         table["e"]  = 2.7182818284590452354;
  206.  
  207.         while (std::cin) {
  208.                 Lexer::get_token();
  209.                 if (Lexer::curr_tok == Lexer::END) break;
  210.                 if (Lexer::curr_tok == Lexer::PRINT) continue;
  211.                 std::cout << Parser::expr(false) << '\n';
  212.         }
  213.  
  214.         return Error::no_of_errors;     
  215. }
  216.